#include "spdlog_logger.h"
#include "logger.h"
#include <spdlog/spdlog.h>
#include <spdlog/sinks/stdout_color_sinks.h>
#include <spdlog/sinks/basic_file_sink.h>
#include <spdlog/sinks/rotating_file_sink.h>
#include <vector>
#include <QCoreApplication>
#include <QDir>

namespace infrastructure {
namespace logging {

// 类型别名简化代码
using LogLevel = kernel::ILogger::LogLevel;

namespace {
struct SinkConfig {
    size_t maxFileSize{5 * 1024 * 1024};  // 默认 5MB
    size_t maxFiles{5};                   // 默认 5 个轮转文件
};

QString ensureLogDir() {
    const QString base = QCoreApplication::applicationDirPath();
    QDir dir(base);
    const QString logDir = dir.filePath(QStringLiteral("logs"));
    QDir logs(logDir);
    if (!logs.exists()) {
        logs.mkpath(QStringLiteral("."));
    }
    return logDir;
}

std::shared_ptr<spdlog::logger> createMultiSinkLogger(const QString& name,
                                                      const QString& logDir) {
    const std::string stdName = name.toStdString();
    if (auto existing = spdlog::get(stdName)) {
        return existing;
    }

    const SinkConfig cfg{};
    const QString filePath = QDir(logDir).filePath(name + QStringLiteral(".log"));

    auto consoleSink = std::make_shared<spdlog::sinks::stdout_color_sink_mt>();
    consoleSink->set_pattern("[%Y-%m-%d %H:%M:%S.%e] [%n] [%^%l%$] %v");
    consoleSink->set_level(spdlog::level::info);

    auto fileSink = std::make_shared<spdlog::sinks::rotating_file_sink_mt>(
        filePath.toStdString(), cfg.maxFileSize, cfg.maxFiles);
    fileSink->set_pattern("[%Y-%m-%d %H:%M:%S.%e] [%n] [%l] %v");
    fileSink->set_level(spdlog::level::info);

    std::vector<spdlog::sink_ptr> sinks{consoleSink, fileSink};
    auto logger = std::make_shared<spdlog::logger>(stdName, sinks.begin(), sinks.end());
    logger->set_level(spdlog::level::info);
    logger->flush_on(spdlog::level::info);

    spdlog::register_logger(logger);
    return logger;
}
}  // namespace

SpdlogLogger::SpdlogLogger(const QString& name)
    : m_name(name) {
    // 尝试从spdlog注册表中获取现有的日志器
    std::string stdName = name.toStdString();
    m_spdlogInstance = spdlog::get(stdName);

    if (!m_spdlogInstance) {
        // 如果不存在，创建一个新的控制台日志器
        m_spdlogInstance = spdlog::stdout_color_mt(stdName);
        m_spdlogInstance->set_level(spdlog::level::info);
        m_spdlogInstance->set_pattern("[%Y-%m-%d %H:%M:%S.%e] [%n] [%^%l%$] %v");
    }
}

SpdlogLogger::SpdlogLogger(const QString& name, std::shared_ptr<spdlog::logger> spdlogInstance)
    : m_name(name), m_spdlogInstance(spdlogInstance) {
}

SpdlogLogger::~SpdlogLogger() = default;

void SpdlogLogger::log(LogLevel level, const QString& message,
                       const char* file, int line, const char* function) {
    if (!m_spdlogInstance) return;

    spdlog::level::level_enum spdLevel = toSpdLogLevel(level);
    std::string msg = message.toStdString();

    if (file && line > 0 && function) {
        msg += QString(" [%1:%2 in %3]").arg(file).arg(line).arg(function).toStdString();
    }

    m_spdlogInstance->log(spdLevel, msg);
}

void SpdlogLogger::debug(const QString& message) {
    if (m_spdlogInstance) {
        m_spdlogInstance->debug(message.toStdString());
    }
}

void SpdlogLogger::info(const QString& message) {
    if (m_spdlogInstance) {
        m_spdlogInstance->info(message.toStdString());
    }
}

void SpdlogLogger::warning(const QString& message) {
    if (m_spdlogInstance) {
        m_spdlogInstance->warn(message.toStdString());
    }
}

void SpdlogLogger::error(const QString& message) {
    if (m_spdlogInstance) {
        m_spdlogInstance->error(message.toStdString());
    }
}

void SpdlogLogger::critical(const QString& message) {
    if (m_spdlogInstance) {
        m_spdlogInstance->critical(message.toStdString());
    }
}

QString SpdlogLogger::name() const {
    return m_name;
}

void SpdlogLogger::setLevel(LogLevel level) {
    if (m_spdlogInstance) {
        m_spdlogInstance->set_level(toSpdLogLevel(level));
    }
}

::kernel::ILogger::LogLevel SpdlogLogger::level() const {
    if (m_spdlogInstance) {
        return fromSpdLogLevel(m_spdlogInstance->level());
    }
    return LogLevel::Info;
}

spdlog::level::level_enum SpdlogLogger::toSpdLogLevel(LogLevel level) const {
    switch (level) {
        case LogLevel::Debug:   return spdlog::level::debug;
        case LogLevel::Info:    return spdlog::level::info;
        case LogLevel::Warning: return spdlog::level::warn;
        case LogLevel::Error:   return spdlog::level::err;
        case LogLevel::Critical: return spdlog::level::critical;
        default: return spdlog::level::info;
    }
}

LogLevel SpdlogLogger::fromSpdLogLevel(spdlog::level::level_enum level) const {
    switch (level) {
        case spdlog::level::debug:    return LogLevel::Debug;
        case spdlog::level::info:     return LogLevel::Info;
        case spdlog::level::warn:     return LogLevel::Warning;
        case spdlog::level::err:      return LogLevel::Error;
        case spdlog::level::critical: return LogLevel::Critical;
        default: return LogLevel::Info;
    }
}

std::shared_ptr<SpdlogLogger> SpdlogLogger::fromGlobalLogger(const QString& name) {
    return std::make_shared<SpdlogLogger>(name);
}

// SpdlogLoggerFactory 实现

SpdlogLoggerFactory::SpdlogLoggerFactory() {
    const QString logDir = ensureLogDir();
    auto logger = createMultiSinkLogger(QStringLiteral("default"), logDir);
    m_defaultLogger = std::make_shared<SpdlogLogger>(QStringLiteral("default"), logger);
}

SpdlogLoggerFactory::~SpdlogLoggerFactory() = default;

std::shared_ptr<::kernel::ILogger> SpdlogLoggerFactory::createLogger(const QString& name) {
    const QString logDir = ensureLogDir();
    auto logger = createMultiSinkLogger(name, logDir);
    return std::make_shared<SpdlogLogger>(name, logger);
}

std::shared_ptr<::kernel::ILogger> SpdlogLoggerFactory::createFileLogger(const QString& name, const QString& filePath) {
    std::string stdName = name.toStdString();
    std::string stdPath = filePath.toStdString();

    // 创建文件日志器
    auto fileLogger = spdlog::basic_logger_mt(stdName, stdPath);
    fileLogger->set_level(spdlog::level::info);
    fileLogger->set_pattern("[%Y-%m-%d %H:%M:%S.%e] [%n] [%^%l%$] %v");

    return std::make_shared<SpdlogLogger>(name, fileLogger);
}

std::shared_ptr<::kernel::ILogger> SpdlogLoggerFactory::createRotatingLogger(
    const QString& name, const QString& filePath, size_t maxSize, size_t maxFiles) {
    std::string stdName = name.toStdString();
    std::string stdPath = filePath.toStdString();

    // 创建滚动文件日志器
    auto rotatingLogger = spdlog::rotating_logger_mt(stdName, stdPath, maxSize, maxFiles);
    rotatingLogger->set_level(spdlog::level::info);
    rotatingLogger->set_pattern("[%Y-%m-%d %H:%M:%S.%e] [%n] [%^%l%$] %v");

    return std::make_shared<SpdlogLogger>(name, rotatingLogger);
}

std::shared_ptr<::kernel::ILogger> SpdlogLoggerFactory::getDefaultLogger() {
    return m_defaultLogger;
}

std::shared_ptr<::kernel::ILogger> SpdlogLoggerFactory::getLogger(const QString& name) {
    std::string stdName = name.toStdString();
    auto spdLogger = spdlog::get(stdName);

    if (spdLogger) {
        return std::make_shared<SpdlogLogger>(name, spdLogger);
    }

    // 如果不存在，创建新的
    return createLogger(name);
}

} // namespace logging
} // namespace infrastructure 
